home *** CD-ROM | disk | FTP | other *** search
- /*
- * Name: GOPSRV EXEC
- * A CMS-based Gopher Server
- * Based on the original, GOPHERD EXEC, from 2.3.
- * Author: Rick Troth, Rice University, Information Systems
- * Date: 1992-Apr-21, Aug-07, Oct-14, Dec-11, 1993-Jan-15
- */
-
- /*
- * Copyright 1993 Richard M. Troth. This software was developed
- * with resources provided by Rice University and is intended
- * to serve Rice's user community. Rice has benefitted greatly
- * from the free distribution of software, therefore distribution
- * of unmodified copies of this material is not restricted.
- * You may change your own copy as needed. Neither Rice
- * University nor any of its employees or students shall be held
- * liable for damages resulting from the use of this software.
- */
-
- /*
- * Calls:
- * GOPSRVLS REXX -- to read files and menus
- * GOPSRVRP REXX -- to resolve gopher paths
- * GOPSRVMB REXX -- to build menus for the client
- *
- * Note: this program does *not* use RXSOCKET's translation
- * option. Translation between ASCII and EBCDIC
- * is determined by the type of file requested.
- */
-
- progid = "CMS Gopher 2.4.0 server"
- gopher = "Gopher"
- timeout = 5
-
- Parse Source . . . . . arg0 .
- argo = arg0 || ':'
- Parse Upper Arg root port . '(' . ')' .
-
- Address "COMMAND"
-
- 'SET LANGUAGE (ADD GOP USER'
-
- host = "localhost" /* this will be reset to the actual name of *
- * this host after RXSOCKET is initialized. */
-
- stdin = 0
- stdout = 1
- stderr = 2
-
- Say argo progid "starting"
-
- logpipe = "CONSOLE"
- _root = Userid()
- _port = 70
- 'PIPE < GOPHERD CONFIG * | STEM CONFIG.'
- If rc = 0 Then
- Do i = 1 to config.0
- If Left(config.i,1) = '*' Then Iterate
- If Left(config.i,1) = '#' Then Iterate
- If Index(config.i,'=') = 0 Then Iterate
- Parse Var config.i var '=' val
- Upper var
- Select /* var */
- When Abbrev("LOGPIPE",var,3) Then logpipe = val
- When Abbrev("ROOT",var,4) Then _root = val
- When Abbrev("PORT",var,4) Then _port = val
- Otherwise 'XMITMSG 2 VAR (ERRMSG'
- End /* Select var */
- End /* Do For */
-
- If root = "" Then root = _root
- If port = "" Then port = _port
-
- If ^Datatype(port,'N') Then Do
- /* "Gopher TCP/IP service port must be numeric." */
- 'XMITMSG 126 (APPLID GOP CALLER SRV ERRMSG'
- Exit 24
- End /* If .. Do */
-
- /*
- * Initialize RXSOCKET
- */
- maxdesc = Socket('Initialize', gopher)
- If maxdesc = "-1" Then Do
- Say argo tcperror()
- Exit -1
- End /* If .. Do */
- Say argo "RXSOCKET Initialized for" maxdesc "descriptors"
-
-
- /*
- * Request the name of this host
- */
- rc = Socket('GetHostName', 'HOST')
- If rc = "-1" Then Do
- Say argo tcperror()
- Exit -1
- End /* If .. Do */
- Say argo "LocalHost =" host
-
-
- /*
- * Request a new socket descriptor (TCP protocol)
- */
- socket = Socket('Socket', 'AF_INET', 'Sock_Stream')
- If socket = "-1" Then Do
- Say argo tcperror()
- Exit -1
- End /* If .. Do */
- Say argo "Primary socket =" socket
-
-
- /*
- * Set this socket to non-blocking mode
- */
- rc = Socket('Ioctl', socket, 'FIONBIO', 1)
- If rc = "-1" Then
- Say argo tcperror()
-
-
- /*
- *
- */
- name = AF_INET || Htons(port)
-
- rc = Socket('Bind', socket, name)
- If rc = "-1" Then Do
- Say argo tcperror()
- Exit -1
- End /* If .. Do */
- Say argo "Bound to port" port
-
-
- /*
- *
- */
- rc = Socket('Listen', socket, maxdesc)
- If rc = "-1" Then Do
- Say argo tcperror()
- Exit -1
- End /* If .. Do */
- /* Say argo "Listening ..." */
-
- /* UNIX and VMS style logging: */
- Parse Value Date('S') With 1 yy 5 mm 7 dd 9 .
- day = Left(Date('W'),3)
- mon = Left(Date('M'),3)
- time = Time()
- userid = Userid()
- /* "Starting gopher daemon" Userid() */
- 'PIPE COMMAND XMITMSG 120 DAY MON DD TIME YY HOST USERID' ,
- '(APPLID GOP CALLER SRV ERRMSG |' logpipe
-
- Say argo progid "waiting for a connection"
-
- 'GLOBALV SELECT GOPHERD PUT HOST PORT ROOT'
-
- Do Forever
-
- rc = FD_ZERO('readmask') /* must be reset each time */
- rc = FD_SET(socket, 'readmask')
- rc = FD_SET(stdin, 'readmask')
-
- Say "*" /* waiting */
- rc = Socket('Select', socket + 1, 'readmask', 0, 0, 0)
- If rc = "-1" Then Do
- Say argo tcperror()
- Leave
- End /* If .. Do */
-
- If FD_ISSET(stdin, 'readmask') = 1 Then Leave
- If FD_ISSET(socket, 'readmask') ^= 1 Then Iterate
-
- /*
- *
- */
- ns = Socket('Accept', socket, 'CLIENT')
- If ns = "-1" Then Do
- Say argo tcperror()
- Leave
- End /* If .. Do */
-
- Say argo "Accepted" ns "at" Time() "client" c2x(client)
- Parse Var client . 5 r1 +1 r2 +1 r3 +1 r4 +1 .
- cipa = c2d(r1) || "." || c2d(r2) || "." || ,
- c2d(r3) || "." || c2d(r4)
- /* Say argo "Client's IP address is" cipa */
-
- /* UNIX and VMS style logging: */
- Parse Value Date('S') With 1 yyyy 5 mm 7 dd 9 .
- day = Left(Date('W'),3)
- mon = Left(Date('M'),3)
- time = Time()
-
- /*
- * Loop, reading the query line from the client.
- */
- path = ""
- Do Forever
-
- rc = FD_ZERO('readmask') /* must be reset each time */
- rc = FD_SET(ns, 'readmask')
-
- rc = Socket('Select', ns + 1, 'readmask', 0, 0, timeout)
- If rc = "-1" Then Do
- Say argo tcperror()
- Exit -1
- End /* If .. Do */
-
- If FD_ISSET(ns, 'readmask') ^= 1 Then Leave
-
- pack = ""
- bytes_in = Socket('Read', ns, 'PACK')
- If bytes_in = "-1" Then
- Say argo tcperror()
- If bytes_in < 1 Then Leave
- If Index(pack,'0A'x) > 0 Then Leave /* ASCII LF */
- If Index(pack,'0D'x) > 0 Then Leave /* ASCII CR */
- path = path || pack
- End
- path = path || pack
-
- Parse Var path path '0A'x . /* ASCII LF */
- Parse Var path path '0D'x . /* ASCII CR */
- 'PIPE VAR PATH | A2E | VAR PATH'
-
- /* refresh disk access (same procedure as used by GONE EXEC) */
- 'PIPE CMS QUERY DISK | DROP | STEM STEM.'
- Do i = 1 to stem.0
- Parse Var stem.i . 8 va 12 fm .
- If Left(va,3) = "DIR" Then Iterate
- 'DISKWRIT' Left(fm,1)
- If rc = 1 Then 'ACCESS' va fm
- End /* Do For */
-
- client = cipa
- 'GLOBALV SELECT GOPHERD PUT CLIENT'
-
-
- Parse Var path path '05'x parm
- Say argo "Requesting:" path
- If parm ^= "" Then Say argo "+ Parms:" parm
-
- Select /* type */
-
- When path = "" Then Do
- type = '1'
- logmsg = 121 /* "Root Connection" */
- End /* When .. Do */
-
- When Left(path,1) = '1' Then Do
- Parse Var path 1 type 2 path
- logmsg = 122 /* "retrieved directory" path */
- End /* When .. Do */
-
- When Left(path,1) = '7' Then Do
- Parse Var path 1 type 2 path
- logmsg = 125 /* "searched directory" path */
- End /* When .. Do */
-
- When Left(path,1) = '/' Then Do
- type = '0'
- logmsg = 123 /* "retrieved file" path */
- End /* When .. Do */
-
- Otherwise Do
- Parse Var path 1 type 2 path
- logmsg = 123 /* "retrieved file" path */
- End /* Otherwise Do */
-
- End /* Select type */
-
- 'GLOBALV SELECT GOPHERD PUT PATH PARM'
- 'GLOBALV SELECT GOPHERD SET MENU'
-
- Select /* type */
-
- When type = "0" Then /* plain text file */
- pipe = 'APPEND LITERAL .' || ,
- '| E2A | SPEC 1-* 1 x0D0A NEXT'
-
- When type = "1" Then /* menu */
- pipe = 'GOPSRVMB | APPEND LITERAL .' || ,
- '| E2A | SPEC 1-* 1 x0D0A NEXT'
-
- When type = "7" Then /* menu with search */
- pipe = 'GOPSRVYS' parm '| GOPSRVMB | APPEND LITERAL .' || ,
- '| E2A | SPEC 1-* 1 x0D0A NEXT'
-
- When type = "9" | , /* binary */
- type = "4" | , /* Mac file, send as binary */
- type = "5" | , /* PC file, send as binary */
- type = "I" | , /* send pictures as binary */
- type = "s" Then /* sound, send as binary */
- pipe = 'FBLOCK 8192' /* default processing */
-
- When type = "p" Then /* PostScript */
- pipe = 'E2A | SPEC 1-* 1 x0D0A NEXT'
-
- When type = "r" | , /* record oriented file */
- type = "v" Then /* var-length records */
- pipe = 'BLOCK 65531 CMS |' pipe
-
- Otherwise /* send it as binary */
- pipe = 'FBLOCK 8192' /* default processing */
-
- End /* Select type */
-
- 'PIPE GOPSRVLS' root '| GOPSRVRP' path ,
- '|' pipe '| FBLOCK 8192 | STEM STEM.'
-
- /* If rc ^= 0 Then logrqest = logrqest "(rc=" || rc || ")" */
-
- 'PIPE COMMAND XMITMSG' logmsg 'DAY MON DD TIME YY CLIENT PATH' ,
- '(APPLID GOP CALLER SRV ERRMSG |' logpipe
-
-
- Say argo stem.0 "blocks to send"
- /*
- * Send the response to our client
- */
- Do i = 1 to stem.0
- bytes_out = Socket('Write', ns, stem.i)
- If bytes_out = "-1" Then Do
- Say argo tcperror()
- Leave
- End /* If .. Do */
- End /* Do For */
-
-
- /*
- * All done, relinquish our socket descriptor
- */
- rc = Socket('Close', ns)
- If rc = "-1" Then Do
- Say argo tcperror()
- Leave
- End /* If .. Do */
- Say argo "Closed" ns "at" Time()
-
-
- End /* Do Forever */
-
-
- /*
- * Tell RXSOCKET that we are done with this IUCV path
- */
- rc = Socket('Terminate')
- If rc = "-1" Then Do
- Say argo tcperror()
- End /* If .. Do */
-
-
- Exit
-
-